//
//  ViewLinable.swift
//  Risac
//
//  Created by remy on 2019/3/9.
//  Copyright © 2019 com.Sac. All rights reserved.
//

import SnapKit

public enum ViewLineType {
    public typealias Line = (UIEdgeInsets, CGFloat, UIColor)
    case none
    case lines(top: Line?, left: Line?, bottom: Line?, right: Line?)
    
    public static func top(_ inset: UIEdgeInsets = .zero, size: CGFloat = Size.onePixel, color: UIColor = tintColor) -> ViewLineType {
        return .lines(top: (inset, size, color), left: nil, bottom: nil, right: nil)
    }
    public static var top: ViewLineType { return self.top() }
    public func top(_ inset: UIEdgeInsets = .zero, size: CGFloat = Size.onePixel, color: UIColor = tintColor) -> ViewLineType {
        if case let .lines(_, left, bottom, right) = self {
            return .lines(top: (inset, size, color), left: left, bottom: bottom, right: right)
        }
        return self
    }
    public var top: ViewLineType { return self.top() }
    
    public static func bottom(_ inset: UIEdgeInsets = .zero, size: CGFloat = Size.onePixel, color: UIColor = tintColor) -> ViewLineType {
        return .lines(top: nil, left: nil, bottom: (inset, size, color), right: nil)
    }
    public static var bottom: ViewLineType { return self.bottom() }
    public func bottom(_ inset: UIEdgeInsets = .zero, size: CGFloat = Size.onePixel, color: UIColor = tintColor) -> ViewLineType {
        if case let .lines(top, left, _, right) = self {
            return .lines(top: top, left: left, bottom: (inset, size, color), right: right)
        }
        return self
    }
    public var bottom: ViewLineType { return self.bottom() }
    
    public static func left(_ inset: UIEdgeInsets = .zero, size: CGFloat = Size.onePixel, color: UIColor = tintColor) -> ViewLineType {
        return .lines(top: nil, left: (inset, size, color), bottom: nil, right: nil)
    }
    public static var left: ViewLineType { return self.left() }
    public func left(_ inset: UIEdgeInsets = .zero, size: CGFloat = Size.onePixel, color: UIColor = tintColor) -> ViewLineType {
        if case let .lines(top, _, bottom, right) = self {
            return .lines(top: top, left: (inset, size, color), bottom: bottom, right: right)
        }
        return self
    }
    public var left: ViewLineType { return self.left() }
    
    public static func right(_ inset: UIEdgeInsets = .zero, size: CGFloat = Size.onePixel, color: UIColor = tintColor) -> ViewLineType {
        return .lines(top: nil, left: nil, bottom: nil, right: (inset, size, color))
    }
    public static var right: ViewLineType { return self.right() }
    public func right(_ inset: UIEdgeInsets = .zero, size: CGFloat = Size.onePixel, color: UIColor = tintColor) -> ViewLineType {
        if case let .lines(top, left, bottom, _) = self {
            return .lines(top: top, left: left, bottom: bottom, right: (inset, size, color))
        }
        return self
    }
    public var right: ViewLineType { return self.right() }
    
    public static var tintColor: UIColor = .black
}

public protocol ViewLinable: RisacCompatible where Self: UIView {}
extension RisacSpace where Base: ViewLinable {
    public var lineType: ViewLineType {
        get {
            return objc_getAssociatedObject(base, AssociationKey.make(#function)) as? ViewLineType ?? .none
        }
        set {
            objc_setAssociatedObject(base, AssociationKey.make(#function), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            lineViewLayout(newValue)
        }
    }
    private var lines: [UIView] {
        get {
            return objc_getAssociatedObject(base, AssociationKey.make(#function)) as? [UIView] ?? []
        }
        set {
            objc_setAssociatedObject(base, AssociationKey.make(#function), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    private func lineViewLayout(_ type: ViewLineType) {
        lines.forEach {
            $0.removeFromSuperview()
        }
        lines = []
        guard case let .lines(top, left, bottom, right) = type else { return }
        if let options = top {
            let view = UIView(frame: .zero, bgColor: options.2)
            base.addSubview(view)
            view.snp.makeConstraints({ (make) in
                make.top.equalTo(options.0.top)
                make.left.equalTo(options.0.left)
                make.right.equalTo(-options.0.right)
                make.height.equalTo(options.1)
            })
            self.lines.append(view)
        }
        if let options = bottom {
            let view = UIView(frame: .zero, bgColor: options.2)
            base.addSubview(view)
            view.snp.makeConstraints({ (make) in
                make.bottom.equalTo(-options.0.bottom)
                make.left.equalTo(options.0.left)
                make.right.equalTo(-options.0.right)
                make.height.equalTo(options.1)
            })
            self.lines.append(view)
        }
        if let options = left {
            let view = UIView(frame: .zero, bgColor: options.2)
            base.addSubview(view)
            view.snp.makeConstraints({ (make) in
                make.left.equalTo(options.0.left)
                make.top.equalTo(options.0.top)
                make.bottom.equalTo(-options.0.bottom)
                make.width.equalTo(options.1)
            })
            self.lines.append(view)
        }
        if let options = right {
            let view = UIView(frame: .zero, bgColor: options.2)
            base.addSubview(view)
            view.snp.makeConstraints({ (make) in
                make.right.equalTo(-options.0.right)
                make.top.equalTo(options.0.top)
                make.bottom.equalTo(-options.0.bottom)
                make.width.equalTo(options.1)
            })
            self.lines.append(view)
        }
    }
}
